package com.study.controller;

import com.study.common.Result;
import com.study.common.RspCodeConstants;
import com.study.common.WebUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 基础controller
 *
 * @author kata
 * @version 2.0, 2017/7/5
 * @since 2.0
 */
public abstract class BaseController {

	private static final Pattern pattern = Pattern.compile("[\u4e00-\u9fa5].*[\\u4e00-\\u9fa5]");
	private static final String SUCCESS = RspCodeConstants.SUCCESS_CODE;
	private static final String ERROR = RspCodeConstants.ERROR_CODE;
	private static final String ERROR_MSG = "系统正忙，请稍候再试";

	protected Logger logger = LoggerFactory.getLogger(this.getClass());

	@ResponseBody
	@ExceptionHandler({RuntimeException.class, Exception.class})
	public Result runtimeExceptionHandler(Throwable e) {
		String errorCode = ExceptionMsg.getCode(e);
		Matcher matcher = pattern.matcher(errorCode == null ? "" : errorCode);
		String msg;

		if (matcher.find()) {
			msg = matcher.group(0);
			errorCode = ERROR;
		} else {
			errorCode = NumberUtils.isDigits(errorCode) ? errorCode : ERROR;
			msg = messageSource.getMessage(errorCode, null, ERROR_MSG, Locale.CHINA);
		}

		logger.error(String.format("code:%s, message:%s", errorCode, msg), e);

		return new Result(errorCode, msg);
	}

	/**
	 * 数据对象正常消息响应体
	 *
	 * @param data 响应数据
	 * @return Result
	 */
	protected <T> Result<T> succeed(T data) {
		Result<T> result = succeed();
		result.setData(data);

		return result;
	}


	protected <T> Result<T> succeed() {

		return new Result<>(SUCCESS, getSuccessMsg(SUCCESS));
	}

	/**
	 * 反回正常提示消息msg
	 *
	 * @param code 消息代码
	 * @return String
	 */
	private String getSuccessMsg(String code) {
		return messageSource.getMessage(code, null, Locale.CHINA);
	}

	private enum ExceptionMsg {
		BIND_EXCEPTION {
			@Override
			protected String getErrorCode(Throwable e) {
				String errorCode;

				if (e instanceof BindException) {
					FieldError fe = ((BindException) e).getBindingResult().getFieldError();
					errorCode = fe.getDefaultMessage();
				} else {
					errorCode = CONSTRAINT_VIOLATION_EXCEPTION.getErrorCode(e);
				}

				return errorCode;
			}

		},
		CONSTRAINT_VIOLATION_EXCEPTION {
			@Override
			protected String getErrorCode(Throwable e) {
				String errorCode = null;

				if (e instanceof ConstraintViolationException) {
					ConstraintViolationException cve = (ConstraintViolationException) e;
					Set<ConstraintViolation<?>> setCv = cve.getConstraintViolations();

					if (!setCv.isEmpty()) {
						ConstraintViolation<?> cv = (ConstraintViolation<?>) setCv.toArray()[0];
						errorCode = cv.getMessage();
					}
				} else {
					errorCode = DEFAULT.getErrorCode(e);
				}

				return errorCode;
			}
		},
		DEFAULT {
			@Override
			protected String getErrorCode(Throwable e) {
				String errorCode = e.getMessage();

				if (StringUtils.isEmpty(errorCode)) {
					errorCode = ERROR;
				}

				return errorCode;
			}
		};

		abstract String getErrorCode(Throwable e);

		public static String getCode(Throwable e) {

			return BIND_EXCEPTION.getErrorCode(e);
		}
	}


	@Resource
	protected MessageSource messageSource;

	@Resource
	protected WebUtils webUtils;

}
